Подтвердить что ты не робот

Определить новый тип памяти

Можно ли определить новый тип памяти. Например, в некоторых компиляторах встроенных систем вы можете сделать это:

__flash const char array[] = "This is memory in flash (not ram) so I can waste it!";

Итак, можно пойти еще более сумасшедшим и определить новый тип памяти (например, SD-карту).

Я в основном спрашиваю, можно ли определить, что такое SD-карта (как получить доступ к данным в ней), а затем объявить переменную в sd-памяти. (каждый раз, когда он видит запись, он вызывает метод sd, каждый раз, когда видит, что он вызывает метод sd):

class SDCard{
public:
  void write(void* data,size_t length);
  void* read(size_t length);
  void* memAlloc(size_t length);

};

__sd char myVar;  //Grabs an address in the sd card based on SDCard::memAlloc
myVar = 'A';  //Calls whatever I defined the sd card write operation as
char other = myVar;  //Calls whatever I defined the sd card read operation as

Я использую gcc, если я могу сделать что-то особенное с этим (я почти готов изменить источник компилятора, чтобы позволить мне это сделать).

Возможно, что-то подобное, но есть несколько проблем:

struct Vol_t{   //Would represent an SD card an external RAM or any other memory
    void write(void* data,size_t len,size_t add) const{}
    void* read(size_t len,size_t add) const{}
};
template<Vol_t* sd, class Type,size_t address>
struct MemDef{  //Wrap your type with this (maybe add -> operator support later
    void operator=(Type&& data){
        sd->write(&data,sizeof(data),address);
    }
    operator Type&(){
        return *reinterpret_cast<Type*>(sd->read(sizeof(Type),address));
    }
};

Vol_t SD;  //Initialize our SD card
MemDef<&SD,int,0xdeadbeaf> sdVar;  //Declare an int variable on the SD card

int main(int argc,char** args){
    sdVar = 12;   //Writes to the SD card
    int local = sdVar;  //Reads from the SD card
    system("Pause");
}

Проблемы с этим подходом:

  • Оптимизатор должен делать каждое чтение/запись ---- не может делать какие-либо оптимизации для переменной, объявленной таким образом. (это основная проблема).
  • Это немного неэлегантно (но он выполняет свою работу)
  • Вы должны указать, какой адрес памяти использовать (было бы замечательно, если бы компилятор мог каким-то образом отобразить все это из до компиляции и автоматически

Поэтому, возможно, мне нужно добавить ключевое слово в gcc (если это так, пожалуйста, укажите мне в правильном направлении, чтобы начать).

Изменить: есть еще одна проблема с этим подходом. Если тип имеет указатель на другую переменную, эта переменная не будет инициализирована на SD-карте (только указатель будет).

4b9b3361

Ответ 1

Могут быть два случая:

  • Аппаратное обеспечение таково, что определенный диапазон адресов сопоставляется с SD-картой, и данные могут быть записаны/прочитаны с SD-карты с использованием обычных инструкций по доступу к памяти в пределах этого диапазона. Используются обычные указатели.
  • Для чтения/записи на SD-карту необходимо использовать специальные инструкции/функции. Например, функция SDCard::read, которая вызывает специальную функцию в ОС (если она есть) или инструкцию прерывания.

__flash является расширением GCC. Он использует другую инструкцию для доступа к памяти и находит данные static в другом сегменте. Но он не может быть обобщен таким образом, используя только С++. Он также не может использоваться с динамическим распределением.

Первый случай (диапазон адресов)

Чтобы использовать обычные указатели для чтения/записи данных на SD-карту, их необходимо пометить volatile. Таким образом, компилятор не оптимизирует и не читает/не пишет. volatile означает, что память может быть изменена/использоваться извне программы, например, аппаратное обеспечение, записывающее ее на SD-карту. См. http://en.cppreference.com/w/cpp/language/cv.

Например

volatile char* data = 0x00010000;
memcpy(data, "test", 5);

записывает "test" на SD-карту, если, например, отображен диапазон памяти 0x00010000.. 0x0001ffff.

Чтобы динамически выделять память на SD-карте, например, с помощью malloc и free для обычной рабочей памяти, потребуется специальный распределитель. Он должен будет обрабатывать сегментирование самой памяти, т.е. Ему нужно отображать, какие области памяти свободны или распределены, а allocate(len) должен найти свободный сегмент длины не менее len. Обычно это обрабатывается операционной системой.

Это может быть написано на С++ как класс распределителя, класс, который должен удовлетворять требованиям Allocator (концепция): http://en.cppreference.com/w/cpp/concept/Allocator. Например (неполное):

template<typename T>
class SD_allocator {
    using value_type = T;
    using pointer = T*;
    pointer allocate(std::size_t len) {} // allocate segment of len bytes
    void deallocate(pointer, std::size_t) {}
};

Если затем можно использовать контейнеры STL, например:

std::vector<int, SD_allocator<int>> vec;

использует память на SD-карте для элементов vec. Здесь они не volatile и предназначены только для использования внутри программы, а не для постоянного хранения на SD-карте.

Стандартный распределитель в С++ - это std::allocator, который выделяет регулярную память, например malloc и free.

Boost, похоже, предоставляет распределитель, который обрабатывает сегментирование в пользовательской определенной области памяти:

http://www.boost.org/doc/libs/1_35_0/doc/html/interprocess/managed_memory_segments.html http://www.boost.org/doc/libs/1_55_0/doc/html/boost/interprocess/allocator.html

Для постоянного хранения, такого как SD-карта, может быть лучше определить фиксированную структуру и макет для данных на SD-карте, а затем прочитать/записать на него.

struct SDCard_data {
    std::int32_t int1;
    std::int32_t buffer1[500];
    std::int8_t padding_[34];
    int four_bit1 : 4;
    int four_bit2 : 4;
    bool bit1:1;
    bool bit2:1;
    bool bit3:1;
    bool bit4:1;
};

static volatile SDCard_data* sdcard
    = reinterpret_cast<volatile SDCard_data*>(0x0001000);

int write_to_card() {
    // writes to the card
    card->int1 = 32;
    card->bit3 = true;
}

Второй случай (специальные инструкции)

Если чтение/запись на SD-карту не соответствуют обычным инструкциям по доступу к памяти на аппаратном обеспечении, данные по ней не могут быть доступны напрямую с помощью указателей raw volatile.

Если целью является доступ к нему таким образом, потребуется класс, например MemDef. Возможно, лучше обработать SD-карту, такую ​​как файл/поток, и вместо этого записать/прочитать целые куски данных в/из нее, используя такие функции, как fopen, fread, fprintf или аналогичные.

Для этого объекты должны быть сериализованы/неэтериализованы. Копирование struct в качестве необработанной памяти, например

struct A;
A a;
write_to_card(reinterpret_cast<void*>(&a), sizeof(A))

работает до тех пор, пока struct является PODType и не содержит указателей/ссылок, то есть типов, внутреннее представление которых зависит на адресах памяти. Он также зависит от компоновки памяти платформы (выравнивание, прокладка структуры), конкретизации, представления float, CHAR_BIT и т.д. Для кросс-платформенной поддержки (например, когда SD-карта считывается с другого устройства с другим микроконтроллером, вместо этого необходимо будет использовать некоторый формат файла.

Также может быть (но сложно) определить пользовательский класс Allocator, который использует класс типа MemDef как тип указателя.

Ответ 2

Ну, в мире С++ для абстрактной памяти обычно вы пишете пользовательский распределитель. Вдоль линий

template <class T>
class SDAlloc {
 public:
   typedef T        value_type;
   typedef T*       pointer;
   typedef const T* const_pointer;
   typedef T&       reference;
   typedef const T& const_reference;
   typedef std::size_t    size_type;
   typedef std::ptrdiff_t difference_type;

   // rebind allocator to type U
   template <class U>
   struct rebind {
       typedef SDAlloc<U> other;
   };

   // return address of values
   pointer address (reference value) const {
       return &value;
   }
   const_pointer address (const_reference value) const {
       return &value;
   }

   SDAlloc(const char* device) {
       // open device by name
       // make helper structures
   }
   ~SDAlloc() {
       // close device
   }

   // return maximum number of elements that can be allocated
   size_type max_size () const throw() {
       return SDsize;
   }

   // allocate but don't initialize num elements of type T
   pointer allocate (size_type num, const void* = 0) {
       // print message and allocate memory on SD
   }

   .......