-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add: testing framework and initial tests #14
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall good.
Few design flaw. Few coding mistakes.
However, the comments are to improve. They are usually shallow and only reflect the meaning of the function name or the next line. Comments should indicate to the reader the possible state of the variable, why we need this function, the limitations of the function, any kind of asserted input/output.
testing/CMakeLists.txt
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As somewhat expected, the tests do not build OOTB, because the decoder require some qemu includes (osdep).
Two options from here:
1. Add a FLAG from the CmakeList.txt file which switch the header in the aforementioned files
2. Use QEMU build system to build the test, tricky but good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you elaborate on the second option? How would it work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented the first option for now.
testing/testing-utils.hh
Outdated
#ifndef TESTING_UTILS_HH | ||
#define TESTING_UTILS_HH | ||
|
||
#include <iostream> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some of these include are not needed anymore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. Fixing.
testing/testing-utils.hh
Outdated
std::string bitmask{""}; | ||
|
||
// Current iteration number (iterates from 0 to numIters - 1) | ||
int currIter; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use coherently the std defined integer (uint8_t, size_t, ....) and c++ defined integer (int, long).
I guess we can use the std defined ones here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixing.
testing/testing-utils.hh
Outdated
Instruction(Args&&... args); | ||
|
||
// Vector to hold pointers to Field objects | ||
std::vector<Field*> fields; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason to use raw pointer instead of reference here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently, we can't store references inside containers like vector in C++. I guess I could use a reference_wrapper object here as well (just like the void Instruction::addField(std::reference_wrapper field) function in testing-utils.cc). That might make even more sense actually since we already take the arguments as reference_wrapper objects.
testing/testing-utils.hh
Outdated
InstructionIterator end() const; | ||
|
||
private: | ||
// Variadic template function to add fields (Field objects or string literals) to the instruction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
variadic
is not an English word
// Variadic template function to add fields (Field objects or string literals) to the instruction | |
// specialized function .. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variadic is the correct technical term I believe: https://en.wikipedia.org/wiki/Variadic
testing/testing-utils.cc
Outdated
bitmask += field->bitmask; | ||
} | ||
// The instruction bitmask must be 32 bits | ||
assert(bitmask.size() == 32 && "Bitmask size must be 32."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your assert is wrongly defined.
assert((void("void helps to avoid 'unused value' warning"), 2 * 2 == 4));
OR
assert((010 + 010 == 16) && "Yet another way to add an assert message");
OR
assertm((2 + 2) % 3 == 1, "Success");
Notice the parentheses around the expression
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
== should have higher precedence than && but will add the parentheses just to make it clearer.
testing/testing-utils.cc
Outdated
assert(bitmask.size() == 32 && "Bitmask size must be 32."); | ||
|
||
// Count the number of don't cares in the instruction bitmask | ||
int numDontCares = std::count(bitmask.begin(), bitmask.end(), 'x'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type coherence
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you again referring to the use of builtin int
instead of stdint types? (Or the lack of consisteny in the usage?)
testing/testing-utils.cc
Outdated
uint32_t result = 0; | ||
|
||
// Generate the instruction based on the bitmask | ||
for (int i = 0, j = 0; i < 32; ++i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid hardcoded number (32, 31)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixing.
testing/testing-utils.cc
Outdated
} | ||
|
||
// Dereference operator to get the current instruction value during range-based for loops | ||
uint32_t Instruction::InstructionIterator::operator*() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why the dereference operator is link to generating an instruction, Shall not the instruction get pre-processed and retrieved by the deref. operator
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wdym by pre-processed? The exact instruction bits (the uint32_t value) for each iteration in for (uint32_t instr : bitmask)
is generated during runtime through the dereference operator.
testing/testing-utils.cc
Outdated
uint32_t Instruction::InstructionIterator::operator*() const { | ||
uint32_t result = 0; | ||
|
||
// Generate the instruction based on the bitmask |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This loop should be a function in Instruction instead of the Iterator.
The loop is slightly unintuitive (basically everything with bitwise operator is); i would suggest decoupling this loop into more functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dereference operator (method) needs to be defined for the Iterator class. I could move the logic to a separate helper function in the Instruction class (and also maybe divide it into multiple functions in the meantime like you said) and call it from the dereference operator in the Iterator class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep the deref. operator is needed for the Iterator, no question. As you said the logic should be moved elsewhere, and maybe pre-processed
Added a testing framework and initial tests for the memory decoder. Two classes called Field and Instruction in the testing-utils.hh file form the testing framework. Some of the initial tests currently fail because of bugs in the memory decoder, and the correct decoder outputs for some instructions (like prefetch instructions) are ambiguous.
To run the tests (while at the top of the qflex repository):
$ cd qemu/middleware/testing
$ cmake -S . -B build
$ cmake --build build -j$(nproc)
$ (cd build && ctest -j$(nproc))