Lazily allocated heap-backed block device. When writing data of ROM address, heap memory is not used.

Dependents:   GR-PEACH-webcam GR-PEACH_DR_STRANGE_VR_GAME GR-Boards_WebCamera

Files at this revision

API Documentation at this revision

Comitter:
dkato
Date:
Tue May 16 04:24:46 2017 +0000
Commit message:
first commit

Changed in this revision

RomRamBlockDevice.cpp Show annotated file Show diff for this revision Revisions of this file
RomRamBlockDevice.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 3e16bac28356 RomRamBlockDevice.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RomRamBlockDevice.cpp	Tue May 16 04:24:46 2017 +0000
@@ -0,0 +1,160 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2017 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RomRamBlockDevice.h"
+
+
+RomRamBlockDevice::RomRamBlockDevice(bd_size_t size, bd_size_t block)
+    : _read_size(block), _program_size(block), _erase_size(block)
+    , _count(size / block), _blocks(0), _rom_start(0xFFFFFFFF), _rom_end(0xFFFFFFFF)
+{
+    MBED_ASSERT(_count * _erase_size == size);
+}
+
+RomRamBlockDevice::RomRamBlockDevice(bd_size_t size, bd_size_t read, bd_size_t program, bd_size_t erase)
+    : _read_size(read), _program_size(program), _erase_size(erase)
+    , _count(size / erase), _blocks(0), _rom_start(0xFFFFFFFF), _rom_end(0xFFFFFFFF)
+{
+    MBED_ASSERT(_count * _erase_size == size);
+}
+
+RomRamBlockDevice::~RomRamBlockDevice()
+{
+    if (_blocks) {
+        for (size_t i = 0; i < _count; i++) {
+            free(_blocks[i]);
+        }
+
+        delete[] _blocks;
+        _blocks = 0;
+    }
+}
+
+void RomRamBlockDevice::SetRomAddr(uint32_t rom_start_addr, uint32_t rom_end_addr) {
+    _rom_start = rom_start_addr;
+    _rom_end = rom_end_addr;
+}
+
+int RomRamBlockDevice::init()
+{
+    if (!_blocks) {
+        _blocks = new uint8_t*[_count];
+        for (size_t i = 0; i < _count; i++) {
+            _blocks[i] = 0;
+        }
+    }
+
+    return BD_ERROR_OK;
+}
+
+int RomRamBlockDevice::deinit()
+{
+    // Heapory is lazily cleaned up in destructor to allow
+    // data to live across de/reinitialization
+    return BD_ERROR_OK;
+}
+
+bd_size_t RomRamBlockDevice::get_read_size() const
+{
+    return _read_size;
+}
+
+bd_size_t RomRamBlockDevice::get_program_size() const
+{
+    return _program_size;
+}
+
+bd_size_t RomRamBlockDevice::get_erase_size() const
+{
+    return _erase_size;
+}
+
+bd_size_t RomRamBlockDevice::size() const
+{
+    return _count * _erase_size;
+}
+
+int RomRamBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
+{
+    MBED_ASSERT(is_valid_read(addr, size));
+    uint8_t *buffer = static_cast<uint8_t*>(b);
+
+    while (size > 0) {
+        bd_addr_t hi = addr / _erase_size;
+        bd_addr_t lo = addr % _erase_size;
+
+        if (_blocks[hi]) {
+            memcpy(buffer, &_blocks[hi][lo], _read_size);
+        } else {
+            memset(buffer, 0, _read_size);
+        }
+
+        buffer += _read_size;
+        addr += _read_size;
+        size -= _read_size;
+    }
+
+    return 0;
+}
+
+int RomRamBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
+{
+    MBED_ASSERT(is_valid_program(addr, size));
+    const uint8_t *buffer = static_cast<const uint8_t*>(b);
+
+    while (size > 0) {
+        bd_addr_t hi = addr / _erase_size;
+        bd_addr_t lo = addr % _erase_size;
+
+        if (isRomAddress(buffer)) {
+            if (!isRomAddress(_blocks[hi])) {
+                free(_blocks[hi]);
+            }
+            _blocks[hi] = (uint8_t*)buffer;
+        } else {
+            if (!_blocks[hi]) {
+                _blocks[hi] = (uint8_t*)malloc(_erase_size);
+                if (!_blocks[hi]) {
+                    return BD_ERROR_DEVICE_ERROR;
+                }
+            }
+            memcpy(&_blocks[hi][lo], buffer, _program_size);
+        }
+
+        buffer += _program_size;
+        addr += _program_size;
+        size -= _program_size;
+    }
+
+    return 0;
+}
+
+int RomRamBlockDevice::erase(bd_addr_t addr, bd_size_t size)
+{
+    MBED_ASSERT(is_valid_erase(addr, size));
+    // TODO assert on programming unerased blocks
+
+    return 0;
+}
+
+bool RomRamBlockDevice::isRomAddress(const uint8_t *address) {
+    if (((uint32_t)address >= _rom_start)
+     && ((uint32_t)address <= (_rom_end - _erase_size + 1))) {
+        return true;
+    }
+    return false;
+}
+
diff -r 000000000000 -r 3e16bac28356 RomRamBlockDevice.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RomRamBlockDevice.h	Tue May 16 04:24:46 2017 +0000
@@ -0,0 +1,148 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2017 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef MBED_ROM_RAM_BLOCK_DEVICE_H
+#define MBED_ROM_RAM_BLOCK_DEVICE_H
+
+#include "BlockDevice.h"
+#include "mbed.h"
+
+
+/** Lazily allocated heap-backed block device
+ *
+ * When writing data of ROM address, heap memory is not used
+ * Useful for simulating a block device and tests
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "RomRamBlockDevice.h"
+ *
+ * RomRamBlockDevice bd(2048, 512); // 2048 bytes with a block size of 512 bytes
+ * uint8_t block[512] = "Hello World!\n";
+ *
+ * int main() {
+ *     bd.SetRomAddr(0x18000000, 0x1FFFFFFF); // ROM Address 0x18000000 - 0x1FFFFFFF
+ *     bd.init();
+ *     bd.program(block, 0);
+ *     bd.read(block, 0);
+ *     printf("%s", block);
+ *     bd.deinit();
+ * }
+ */
+class RomRamBlockDevice : public BlockDevice
+{
+public:
+
+    /** Lifetime of the memory block device
+     */
+    RomRamBlockDevice(bd_size_t size, bd_size_t block=512);
+    RomRamBlockDevice(bd_size_t size, bd_size_t read, bd_size_t program, bd_size_t erase);
+    virtual ~RomRamBlockDevice();
+
+    /** Set the ROM address range
+     * 
+     *  When writing data of ROM address, heap memory is not used
+     * 
+     *  @param rom_start_addr   Rom start address
+     *  @param rom_end_addr     Rom end address
+     */
+    void SetRomAddr(uint32_t rom_start_addr, uint32_t rom_end_addr);
+
+    /** Initialize a block device
+     *
+     *  @return         0 on success or a negative error code on failure
+     */
+    virtual int init();
+
+    /** Deinitialize a block device
+     *
+     *  @return         0 on success or a negative error code on failure
+     */
+    virtual int deinit();
+
+    /** Read blocks from a block device
+     *
+     *  @param buffer   Buffer to read blocks into
+     *  @param addr     Address of block to begin reading from
+     *  @param size     Size to read in bytes, must be a multiple of read block size
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual int read(void *buffer, bd_addr_t addr, bd_size_t size);
+
+    /** Program blocks to a block device
+     *
+     *  The blocks must have been erased prior to being programmed
+     *
+     *  @param buffer   Buffer of data to write to blocks
+     *  @param addr     Address of block to begin writing to
+     *  @param size     Size to write in bytes, must be a multiple of program block size
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size);
+
+    /** Erase blocks on a block device
+     *
+     *  The state of an erased block is undefined until it has been programmed
+     *
+     *  @param addr     Address of block to begin erasing
+     *  @param size     Size to erase in bytes, must be a multiple of erase block size
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual int erase(bd_addr_t addr, bd_size_t size);
+
+    /** Get the size of a readable block
+     *
+     *  @return         Size of a readable block in bytes
+     */
+    virtual bd_size_t get_read_size() const;
+
+    /** Get the size of a programable block
+     *
+     *  @return         Size of a programable block in bytes
+     */
+    virtual bd_size_t get_program_size() const;
+
+    /** Get the size of a eraseable block
+     *
+     *  @return         Size of a eraseable block in bytes
+     */
+    virtual bd_size_t get_erase_size() const;
+
+    /** Get the total size of the underlying device
+     *
+     *  @return         Size of the underlying device in bytes
+     */
+    virtual bd_size_t size() const;
+
+private:
+    bd_size_t _read_size;
+    bd_size_t _program_size;
+    bd_size_t _erase_size;
+    bd_size_t _count;
+    uint8_t **_blocks;
+    uint32_t _rom_start;
+    uint32_t _rom_end;
+
+    bool isRomAddress(const uint8_t *address);
+};
+
+
+#endif