tum-ei-eda / m2-isa-r Goto Github PK
View Code? Open in Web Editor NEWCoreDSL2 Parser with backend to generate simulation code for the ETISS instruction set simulator
Home Page: https://tum-ei-eda.github.io/M2-ISA-R/
License: Apache License 2.0
CoreDSL2 Parser with backend to generate simulation code for the ETISS instruction set simulator
Home Page: https://tum-ei-eda.github.io/M2-ISA-R/
License: Apache License 2.0
I realized in the below operation wrong return value Z
is generated during the summation of X and Y:
unsigned<64> foo(unsigned<32> X, unsigned<32> Y){
unsigned<64> Z = X + Y;
return Z;
}
I believe this is due to the fact that X
and Y
are translating to C types (etiss_uint32
) and their summation also returns etiss_uint32
which drops the overflow value(32nd bit).
However when I do casting explicitly as follows:
unsigned<64> foo(unsigned<32> X, unsigned<32> Y){
unsigned<64> Z = (unsigned<64>)X + (unsigned<64>)Y;
return Z;
}
It works pretty well.
But coredsl2 manual guarantees no dropping is occurring by simply setting the width of the result value to wr = max(w1 + 1, w2 + 1)
. Should not M2-ISA-R also guarantee this? This is leading to a lot of unexpected behaviors.
Thanks a lot!
If the index to the register file for data writeback is not static (i.e. not constant or not part of the instruction encoding), M2-ISA-R has issues getting the scope right. I guess this is a rare edge case, as it is generally not allowed to index the register file using "runtime data" (normally the source and destination register indexes are part of the instruction itself, correct me if I am wrong here). However, the CIW, CL, CS, and CB encodings of the compressed instruction set allow only a subset of the 32 register file to be accessed. Therefore, they only allow access to 8 registers (hence the 3 bit wide rs1
field below). This is elegantly implemented in the CoreDSL by adding 8 to the 3bit rs1
index, thus allowing access to registers x8-x15
.
For example, let us have a look at the compressed shift right logical immediate instruction:
C.SRLI {//(RV32 nse)
encoding:b100 | b0 | b00 | rs1[2:0] | shamt[4:0] | b01;
args_disass: "{name(8+rs1)}, {shamt}";
val rs1_idx[5] <= rs1+8;
X[rs1_idx] <= shrl(X[rs1_idx], shamt);
}
which generates the following behaviour code:
...
1:etiss_uint32 shamt = 0;
2: static BitArrayRange R_shamt_0(6, 2);
3: shamt += R_shamt_0.read(ba) << 0;
4: etiss_uint32 rs1 = 0;
5: static BitArrayRange R_rs1_0(9, 7);
6: rs1 += R_rs1_0.read(ba) << 0;
7:
8: // -----------------------------------------------------------------------------
9:
10: CodePart & partInit = cs.append(CodePart::INITIALREQUIRED);
11:
12: partInit.code() = std::string("//C.SRLI\n");
13:
14: // -----------------------------------------------------------------------------
15: partInit.code() += "etiss_uint8 rs1_idx = (" + std::to_string(rs1 + 8) + ") & 0x1f;\n";
16: partInit.code() += "*((RISCV*)cpu)->X[rs1_idx] = (*((RISCV*)cpu)->X[rs1_idx]) >> (" + std::to_string(shamt) + ");\n";
17: partInit.code() += "cpu->instructionPointer = " + std::to_string(ic.current_address_ + 2) + ";\n";
18: // -----------------------------------------------------------------------------
19:
20: partInit.getRegisterDependencies().add(reg_name[rs1_idx], 32);
21: partInit.getAffectedRegisters().add(reg_name[rs1_idx], 32);
22: partInit.getAffectedRegisters().add("instructionPointer", 32);
...
While the "static" variables in lines 1-6 work just fine, the addition in the behaviour part of the instruction in line 15 causes the rs1_idx
variable to be in the scope of the jit code. This raises an error in lines 20-21 when rs1_idx is referenced outside the jit code.
Now a simple fix would be to get rid of the rs1_idx
variable, like so:
C.SRLI {//(RV32 nse)
encoding:b100 | b0 | b00 | rs1[2:0] | shamt[4:0] | b01;
args_disass: "{name(8+rs1)}, {shamt}";
X[ rs1+8] <= shrl(X[ rs1+8], shamt);
}
However, this would make M2-ISA-R not compatible with the RISC-V CoreDSLs provided by Minres.
Another approach would be to detect if an assignment is completely "static" and then put its "target" variable outside the jit code (this would help ETISS runtime performance as well).
Or one could inline such simple expressions at compile-time, producing my "hand-optimized" code from above,. However, this is probably the most labour intensive approach concerning the required changes to M2-ISA-R.
void pctest(int a, int b) {
X[a] = PC;
PC = X[b];
}
is translated to:
static inline void pctest(ETISS_CPU * const cpu, ETISS_System * const system, void * const * const plugin_pointers, etiss_int32 a, etiss_int32 b)
{
((test_core*)cpu)->X[a] = ic.current_address_;
cpu->instructionPointer = ((test_core*)cpu)->X[b];
}
where ic.current_address_
can not be accessed in function context.
Defined in CoreDSL2 functions, which have memory access, are generated with "partInit.code" sections. Because of this issue, these functions cannot be called during the simulation.
As of now, M2-ISA-R does not generate any code for register printing via GDB in RISCVVGDBCore.h
. It only provides a comment Further register should be added here to send data over gdbserver
. Is that intended?
The ArchImpl in ETISS has the mapRegister method already implemented.
Hello
I just realized the following code:
architectural_state {
extern unsigned<8> ITSTATE;
}
bool it_passed(){
unsigned<4> cond = 0;
if(ITSTATE[3:0] != 0)
cond = ITSTATE[7:4];
else if(ITSTATE==0)
cond = 14;
bool result = condition_passed(cond);
///// advance IT
if (ITSTATE[2:0]== 0) ITSTATE=0;
else states = ITSTATE[7:5] :: (unsigned<6>) LSL(ITSTATE[4:0], 1);
return result;
}
is producing the following code:
// in ARMv7M.h file
etiss_uint8 ITSTATE;
static inline etiss_uint8 it_passed (ETISS_CPU * const cpu, ETISS_System* const system, void* const* const plugin_pointers)
{
etiss_uint8 cond = (0U) & 0xf;
if (((ARMv7M*)cpu)->ITSTATE[3U] & 1U)
cond = (((ARMv7M*)cpu)->ITSTATE[7U]) & 0xf;
else
if (((ARMv7M*)cpu)->ITSTATE == 0U)
cond = (14U) & 0xf;
etiss_uint8 result = (condition_passed(cpu, system, plugin_pointers, cond)) & 0x1;
if (((ARMv7M*)cpu)->ITSTATE[2U] == 0U)
((ARMv7M*)cpu)->ITSTATE = 0U;
else
((ARMv7M*)cpu)->ITSTATE = (((((ARMv7M*)cpu)->ITSTATE[7U])<< 6) | ((etiss_uint8)((LSL(((ARMv7M*)cpu)->ITSTATE[4U], 1U) & 0x3f))));
return result;}
where you might have already seen the resulting indexes of ITSTATE
after slicing are completely wrong.
However when I create a local copy of the extern variable ITSTATE
as follows:
architectural_state {
extern unsigned<8> ITSTATE;
}
bool it_passed(){
unsigned<4> cond = 0;
unsigned<8> states = ITSTATE; /// local copy of the same type
if(states[3:0] & 0xf != 0)
cond = states[7:4];
else if(states == 0)
cond = 14;
bool result = condition_passed(cond);
///// advance IT
if (states[2:0] == 0) states = 0;
else states = states[7:5] :: (unsigned<6>)LSL(states[4:0], 1);
ITSTATE = states; // put the result back
return result;
}
The following true expected code is generated.
static inline etiss_uint8 it_passed (ETISS_CPU * const cpu, ETISS_System* const system, void *const * const plugin_pointers){
etiss_uint8 cond = (0U) & 0xf;
etiss_uint8 states = ((ARMv7M*)cpu)->ITSTATE;
if ((((states) >> (0U)) & 15) & 1U)
cond = ((((states) >> (4U)) & 15)) & 0xf;
else
if (states == 0U)
cond = (14U) & 0xf;
etiss_uint8 result = (condition_passed(cpu, system, plugin_pointers, cond)) & 0x1;
if ((((states) >> (0U)) & 7) == 0U)
states = 0U;
else
states = ((((((states) >> (5U)) & 7)) << 6) | ((etiss_uint8)((LSL((((states)>> (0U)) & 31), 1U) & 0x3f))));
((ARMv7M*)cpu)->ITSTATE = states;
return result;}
But why this is happening in the first place even though states
and ITSTATE
are of the same type of etiss_uint8
? Is there something wrong with extern variables?
Thanks
Signed registers declared in the CoreDSL2 model are converted to unsigned in ETISS.
M2-ISA-R currently produces "nested" static statements by calling make_static()
on statements that were already made static. This leads to code like this:
partInit.code() += "_illmask = " + std::to_string((1) << (" + std::to_string(32 - 1) + ")) + ";\n";
See 16e0bcb for an extremely dirty fix.
Currently the code for inserting memory access functions in the ETISS model is duplicated all over instruction_transform.py, this should be consolidated at one single point for ease of reading and maintenance.
CoreDSL return PC + 2;
yields in C return ${PC} + 2U;
.
I was following the coredsl2 manual and I am having trouble using the concatenation operator during etiss code generation phase.
As an example the following behavioral model:
is generating the following code:
where imm
is shifted 3 times although it should have been shifted by 2.
is generating the following code:
where im11
has not been shifted at all.
I am not sure if I am missing something or this is a possible bug. Do you have any idea?
Requested from ETISS: tum-ei-eda/etiss#122
Open questions:
X[0]
... ?Hello,
the following coredsl2 code:
void foo(){
unsigned<8> a = 3;
unsigned<8> b = 1;
unsigned<32> x = 0, y=0;
unsigned<64> z = x::y[a:b];
}
is producing:
static inline void foo (){
etiss_uint8 a = 3U;
etiss_uint8 b = 1U;
etiss_uint32 x = 0U;
etiss_uint32 y = 0U;
etiss_uint64 z = (((x) << 32) | ((((y) >> (b)) & ((1 << ((a) - (b) + 1)) - 1))));
}
where x has been shifted 32
times instead of a - b + 1
times.
However, putting numbers into slices:
void foo(){
unsigned<32> x = 0, y=0;
unsigned<64> z = x::y[3:1];
}
works quite well:
static inline void foo (){
etiss_uint32 x = 0U;
etiss_uint32 y = 0U;
etiss_uint64 z = (((x) << 3) | ((((y) >> (1U)) & 7)));
}
any idea about this?
The following code does not work with the CoreDSL2 frontend and the ETISS backend:
VXSAT_CSS[0] = 0b1;
As a workaround VXSAT_CSR = VXSAT_CSR | 0b1;
works just fine.
Hello,
I have noticed that a memory access placed inside of an if statement does not generate code for actually reading the memory.
A small example:
This behavior describtion generates the following code:
behavior: {
if ((signed<32>)MEM[0] > 0)
X[1] = 1;
}
partInit.code() += "cpu->instructionPointer = " + std::to_string(ic.current_address_ + 4U) + ";\n";
partInit.code() += "if ((etiss_int32)(mem_val_0) > 0U) {\n";
partInit.code() += "*((RV32IMACFD*)cpu)->X[" + std::to_string(1U) + "] = 1U;\n";
partInit.code() += "}\n";
Where I would have expected it to generate the code below or throw an error.
partInit.code() += "cpu->instructionPointer = " + std::to_string(ic.current_address_ + 4U) + ";\n";
partInit.code() += "etiss_uint32 mem_val_0;\n";
partInit.code() += "exception |= (*(system->dread))(system->handle, cpu, "
+ std::to_string(0U) + ", (etiss_uint8*)&mem_val_0, 4);\n";
partInit.code() += "if ((etiss_int32)(mem_val_0) > 0U) {\n";
partInit.code() += "*((RV32IMACFD*)cpu)->X[" + std::to_string(1U) + "] = 1U;\n";
partInit.code() += "}\n";
Thanks
I think it would be helpful to include an example folder that would contain some basic RISCV core modelled in CoreDSL. This could be used to quickly get going and test whether M2-ISA-R is working. One could also use it to run some automated tests using unittest and GitHub actions (including a status badge and what not... :)). Let me know if you think this is useful and I will create a PR.
In the long run, it could be beneficial to have a separate CoreDSL Model repository here on GitHub, similar to the one you have on GitLab @wysiwyng. This Model repository could then be included as a submodule. As this tool is the only way one can actually use the CoreDSL Models for anything meaningful, I would find this "relative tight coupling" between models and generator not too problematic.
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.