-
Notifications
You must be signed in to change notification settings - Fork 3k
Implement FlashSimBlockDevice - flash simulated block device over RAM #6559
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
Conversation
Ah! This looks great. Though do you think it would be possible to make this a block device adapter? That way you could use it on top of any block device without a proper erase: // Flash on heap
HeapBlockDevice heap(512, 512*1024);
FlashSimBlockDevice sim(&heap);
// Flash on I2C EEPROM
I2CEEBlockDevice i2c(D11, D12);
FlashSimBlockDevice sim(&i2c); Thoughts? Sorry if this is more effort to implement. |
No big deal. This is indeed a cleaner solution. |
0aa6320
to
0dfae76
Compare
Updated as a BD adaptor. |
0dfae76
to
16391e8
Compare
#include <algorithm> | ||
#include <stdlib.h> | ||
|
||
static const uint8_t blank = 0xFF; |
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.
Do you think we should make this configurable in the constructor? Since this variable is the point of the 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.
Good question. Would argue that this value is device specific, and that a user of either this class or a real flash block device would need to read this value via the get_erase_value
API, hence wouldn't be interested in the predefined value.
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.
In that case I suggest we should add an API to block device class to read this value from block device
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.
There is such an API - get_erase_value
, and this class implements it (just returns blank
).
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.
Sorry missed that. If it is device specific and not application/user specific we can have a macro and target device based on the RAM in hardware can define this macro in targets.json macro
section. But I am not sure if any RAM device will have erase state as 0.
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 are right. If the underlying BD's erase value is 0xFF, this will not work well (as we will allow programming of unerased blocks). Will add a parameter to the constructor (with a default value of 0xFF).
return ret; | ||
} | ||
_blank_buf_size = align_up(min_blank_buf_size, _bd->get_read_size()); | ||
_blank_buf_size = align_up(_blank_buf_size, _bd->get_program_size()); |
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.
non-blocker: Program size must be a multiple of the read size for the BlockDevice API, so you probably don't need both of these align-ups.
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.
Maybe not blocking, but also not very nice. Will fix.
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.
Looks good to me 👍 Thanks for putting this together
bd_size_t curr_size = size; | ||
|
||
while (curr_size) { | ||
bd_size_t read_size = std::min(_blank_buf_size, curr_size); |
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.
Query: What should be the value of _blank_buf_size
in case read size of block device is 1 byte and program size is 512 bytes. ?
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.
From code it looks like blank_buf size
and buffer
parameters are to find out if the buffer is blank to be programmed then program it else erase (which is re-program with 0x0/0xFF) first.
If my understanding is correct then you don;t have to consider read size at all, it should be atleast program size big always.
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.
Right. Also raised by @geky. Will fix.
#include <stdlib.h> | ||
|
||
static const uint8_t blank = 0xFF; | ||
static const bd_size_t min_blank_buf_size = 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.
I think even min_blank_buf_size
should be configurable
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.
Can you explain? Was trying to define a value that should be small enough, so it wouldn't effect heap usage. Do you think it should be smaller? A larger value can make the blank programming/checking a bit more efficient, but this seems negligible to me.
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.
It depends on the use case of this class. If you have it as variable, we keep it configurable for application to have more flexibility.
Ideally for me it should be equivalent to program size and not separate parameter. (As in case of real flash only if entire programmable block is empty than we can say it is free and not by checking few bytes of block)
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.
Ah, I think you missed the purpose of this buffer. If you look at the code (both in erase and program APIs) you'll see that the entire prog_size is checked. This buffer is just used as an intermediate one for this purpose, read/programmed in a few iterations until prog_size is reached.
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.
Yeah I am kind of confused with the usage of this buffer, instead of having it equivalent to program size it is less to save on heap space, and since it is RAM the iterations will be fast. But in the test example program size (8) is less then blank buffer size (32), shouldn't we cap it to program size.
If you would have used defines, and static allocation I would not have made this argument, but we are using dynamic allocation 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.
Capping it to program size will make it extremely inefficient if program size is 1 (saw flash devices with such parameters), meaning that both program and erase functions will read/write chunks of 1. Hence the minimum of 32, which should work even if program size is 1.
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.
Looks good to me 👍
16391e8
to
4a169b6
Compare
Pushed a fix with the following:
|
b8609c1
to
cb992de
Compare
Can you please use approve/request changes rather than comment (helps to see the actual status in reviewers) ? |
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.
Looks great 👍
This will be a nice block device wrapper to have
waiting for @SenRamakri approval, meanwhile /morph build |
Build : SUCCESSBuild number : 1707 Triggering tests/morph test |
@AnotherButler Please review documentation |
Sorry, figured out the problem (pointer increment in an optimized condition). Should be OK now. |
Build : SUCCESSBuild number : 1923 Triggering tests/morph test |
Test : SUCCESSBuild number : 1743 |
Exporter Build : SUCCESSBuild number : 1568 |
Waiting for approvals @davidsaada Docs will be added here as a reference (handbook PR) ? |
38cea35
to
c3e3999
Compare
Pushed astyle related fixes |
Doc PR here. |
/morph build |
Requesting re-review from reviewers. Should be quick. |
Build : SUCCESSBuild number : 2028 Triggering tests/morph test |
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.
Looks great to me 👍
Test : FAILUREBuild number : 1834 |
Exporter Build : SUCCESSBuild number : 1677 |
That is correct, we noticed the failures today morning. We will restart all jobs as soon as the devices are back running (just restart does not help in this case). |
_blank_buf_size = align_up(min_blank_buf_size, _bd->get_program_size()); | ||
if (!_blank_buf) { | ||
_blank_buf = new uint8_t[_blank_buf_size]; | ||
MBED_ASSERT(_blank_buf); |
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.
Non blocking and can be fixed in future - New will assert if memory allocation fails, additional check is not needed. Do you intent to use malloc instead 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.
Thanks, will remove the redundant check. And no - will keep using new[].
/morph test |
1 similar comment
/morph test |
Test : SUCCESSBuild number : 1853 |
Description
Implement a simulated flash block device over RAM. This will allow us to test features that use flash block devices (like StorageLite) on targets that don't have a real flash block device (practically all targets).
Pull request type
[ ] Fix
[ ] Refactor
[ ] New target
[X ] Feature
[ ] Breaking change