tum-ei-eda / etiss Goto Github PK
View Code? Open in Web Editor NEWExtendable Translating Instruction Set Simulator
Home Page: https://tum-ei-eda.github.io/etiss/
License: Other
Extendable Translating Instruction Set Simulator
Home Page: https://tum-ei-eda.github.io/etiss/
License: Other
The chocolatey package (and the official llvm installer) do not provide the required cmake files for FIND_PACKAGE
.
See https://groups.google.com/g/llvm-dev/c/BT3fCvN6DCk
The solutions do not seem great:
FIND_PACKAGE
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:
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
See title, as ETISS requires LLVM 11 or greater per the cmake file, this should also be reflected in the CI.
This issue summarizes the functionality of the existing Fault Injection Code in ETISS and lists existing problems with it:
The core concept is that a VirtualStruct
, aka an Injector
, checks whether one of its assigned Trigger
s is satisfied and then applies the corresponding Action
s through the static Stressor
that manages all Fault
s registered through ETISS' configuration.
A Fault
has a set of Trigger
s and a set of Action
s.
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
firesVARIABLEVALUE
: The trigger condition is satisfied if the associated variable Field
is equal to a constant valueTIME
: The trigger condition is satisfied, if ETISS simulation time has reached the given constant time value of the triggerTIMERELATIVE
: On the first check of the Trigger
condition the given time value is added to the current simulation time to make a TIME
type triggerNOP
: No trigger operation - invalidExisting 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 Injector
s applyCustomAction with the given string as an argument.INJECTION
: Injects a new Fault
into the simulation, e.g., see TIMERELATIVE
TriggerNOP
: No Action operation - invalidAction
being applied by the Stressor
all VirtualStruct
s, e.g., the CPUCore, have to be mounted to the static VirtualStruct::root()
. This is needed to allow the Stressor
to resolve all Injector
s 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 Trigger
s and Action
s lead to simulation errors instead of "don't care"s.Stressor::firedTrigger
calling Stressor::addFault
in INJECTION
type Action
s result in deadlock because both take same mutex.Field
fault capability with only supporting BITFLIPS
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
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:
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
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.
getenforce
exists and returns Enforcing
.ETISS_SELINUX
), which the user has to set accordingly.I am not sure what the best approach would be here, option 1 would definitely be the most user-friendly one.
see: runs/3857645364 a rerun of a previously successful run.
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 ETISSetiss.log_pc
is only checked in the example bare etiss processor to activate an additional pluginvp.sw_binary_ram
no usage, deprecated since existing SystemWrappers now rely on ELF filesvp.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:
Lines 721 to 753 in 36902d3
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._
Reason is variables are declarated multiple times in the same compound, e.g.:
1),
etiss/ArchImpl/RISCV64/RISCV64Arch.cpp
Line 10928 in ba3ca84
etiss/ArchImpl/RISCV64/RISCV64Arch.cpp
Line 10952 in ba3ca84
Problem might be traced back to Code Generator for ArchImpl.
etiss::initialize(std::vectorstd::string args)
declares a function used by etiss::Initializer::Initializer
without being declared. Declaration got lost with commit f9080b6d9e3fcbfefe5fc89d1ec67c5fd4f30bcd
This issue breaks the usage of etiss::Initializer with "primitive" command line option pass int argc, [const] char** argv
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:
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.
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;
}
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
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
Try to fix all warnings
Currently the core and plugin configurations are separated by sections in the config file. Only the core part can be overwritten by cmdline args however.
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.
etiss/src/IntegratedLibrary/gdb/GDBServer.cpp
Lines 342 to 360 in 9c9a037
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.
@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.
Remove it or test with MSVC "/W4" flag.
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.
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
This required major revisions to various ETISS components. As of now, virtual memory is not supported.
Compile the core and all available plugins into a single binary.
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
Note sure if this is the correct fix:
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
It is not technically required and has odd requirements (trailing path separator)
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.
Sort source file based on topics (JIT; Peripherals; etc)
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.
The current ones only test performance of the translated code.
Something like the following should be fine
.global main
main:
.rept 10000000
nop
.endr
li a0, 0
ret
An error should be reported instead.
This is important for automated testing.
Title. The error message which is printed in Instruction.h suggests that InstructionDefinition
s with missing callbacks will be ignored, but not the termination of ETISS. What is the desired behavior here?
Make the code compile clean with clang-tidy
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.
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.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
do we want to support RV64G ISA in examples? Currently i see that:
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 optionrv64
in run_helper.sh
doesn't seem to work as ETISS crashes with unrecognized optionI seem to have accidentally dropped the job with this: ec9e71a
Do we want to use travis again or port the flow to GH Actions?
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...
When uncommenting
etiss/ArchImpl/RISCV/RISCVArchSpecificImp.h
Line 386 in 4c36313
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:
Line 739 in 4c36313
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.
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:
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.
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.
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.
The key specifying the JIT type was changed in 5995314, but this change was not reflected in run_helper.sh.
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.