2016-04-15 6 views
23

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

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

Итак, можно пойти еще безумнее и определить новый тип памяти (как, скажем, в 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"); 
} 

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

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

Так может быть, я должен добавить ключевое слово в НКУ (если это так, пожалуйста, мне точку в правильном направлении, чтобы начать)

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

+4

ты говоришь о голом железе приложения или сценарий с поддержкой ОС? __flash работает над встроенным, потому что GCC помещает «свернутые» данные в специальный раздел (например .progmem.data в AVR), GCC также знает, что он должен читать эти данные с помощью команды LPM ... –

+1

Нет, доступное из этого адресного пространства является целевым. Другими словами, он должен иметь смысл для конкретного процессора, для которого вы компилируете код. – Pemdas

+0

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

ответ

9

Там может быть два случая:

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

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

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

Чтобы использовать обычные указатели для чтения/записи данных на 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. Обычно это обрабатывается операционной системой.

Это можно записать в C++ как Распределитель класс, класс, который должен выполнить требования 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-карте.

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

подталкивания, кажется, обеспечивает аллокатор, который обрабатывает сегментацию, на настраиваемую определяются область памяти:

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-карту, не соответствуют стандартным инструкциям доступа к памяти на оборудовании, на нем данные не могут быть доступны непосредственно с использованием исходных 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

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

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 
    } 

    ....... 
Смежные вопросы