2016-04-15 10 views
23

È possibile definire un nuovo tipo di memoria. Per esempio in alcuni sistemi compilatori integrati si può fare questo:Definire un nuovo tipo di memoria

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

Quindi è possibile andare ancora più pazzo e definire un nuovo tipo di memoria (come dire una scheda SD).

In sostanza sto chiedendo è possibile definire cosa sia una scheda SD (come accedere ai dati in esso) e quindi dichiarare una variabile nella memoria SD. (Ogni dove si vede una scrittura chiama il metodo SD, in ogni dove si vede una lettura chiama il metodo 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 

Sto usando gcc se posso fare qualcosa di speciale con che (io sono quasi pronto per modificare l'origine del compilatore per consentirmi di farlo).

Qualcosa di simile a questo è possibile, ma ci sono alcuni problemi:

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"); 
} 

problemi con questo approccio:

  • Optimizer deve fare ogni singola lettura/scrittura ---- esso non can fare qualche ottimizzazione su una variabile dichiarata in questo modo. (questo è il problema principale)
  • È un po 'poco elegante (ma ha il compito finito)
  • Devi specificare quale indirizzo di memoria usare (Sarebbe fantastico se il compilatore potesse in qualche modo capire tutto questo out prima compilazione e automaticamente

Così forse devo aggiungere una parola chiave per gcc (se questo è il caso, per favore mi punto nella giusta direzione per iniziare)

Edit:. lì è un altro problema con questo approccio e ha un puntatore a un'altra variabile che la variabile non sarà inizializzata sulla scheda SD (solo il puntatore lo farà).

+4

stai parlando di un'applicazione di metallo nudo o uno scenario supportato dal sistema operativo? __flash funziona su embedded perché GCC mette i dati "lampeggianti" in una sezione speciale (ad esempio .progmem.data in AVR), GCC sa anche che deve leggere quei dati con l'istruzione LPM ... –

+1

No, lo spazio disponibile per l'indirizzo è specifico per target. In altre parole, deve avere un significato per il processore specifico per il quale si sta compilando il codice. – Pemdas

+0

Questo sarà un sistema integrato. In sostanza, sto chiedendo che sia possibile definire cosa sia una scheda SD (come accedere ai dati in essa contenuti) e quindi dichiarare una variabile nella memoria. (ogni dove vede una scrittura chiama il metodo sd, ogni dove vede una lettura chiama il metodo sd). – DarthRubik

risposta

9

Ci potrebbero essere due casi:

  1. L'hardware è tale che un certo intervallo di indirizzi mappe sulla scheda SD, ed i dati possono essere scritti/letti dalla scheda SD utilizzando normali istruzioni di accesso alla memoria, all'interno di tale intervallo. Vengono usati puntatori regolari.
  2. È necessario utilizzare istruzioni/funzioni speciali per leggere/scrivere sulla scheda SD. Ad esempio una funzione SDCard::read, che richiama una funzione speciale sul sistema operativo (se presente) o un'istruzione di interruzione.

__flash è un'estensione GCC. Utilizza un'istruzione diversa per accedere alla memoria e individua i dati static su un altro segmento. Ma non può essere generalizzato in questo modo usando solo C++. Inoltre, non può essere utilizzato con l'allocazione dinamica.

Primo caso (intervallo di indirizzi)

Per utilizzare puntatori regolari per leggere/scrivere dati sulla scheda SD, hanno bisogno di essere segnata volatile. In questo modo il compilatore non ottimizza e legge/scrive. volatile significa che la memoria può essere modificata/utilizzata all'esterno del programma, ad esempio l'hardware che lo scrive su una scheda SD. Vedi http://en.cppreference.com/w/cpp/language/cv.

Per esempio

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

scrive "test" sulla scheda SD, se per esempio l'intervallo di memoria 0x00010000 .. 0x0001ffff mappe ad esso.

Per allocare dinamicamente memoria sulla scheda SD, come con malloc e free per la memoria di lavoro normale, sarebbe necessario un allocatore personalizzato. Dovrebbe gestire la segmentazione della memoria stessa, ovvero deve mappare quali aree della memoria sono libere o allocate, e allocate(len) deve trovare un segmento libero di lunghezza almeno len. Questo è normalmente gestito dal sistema operativo.

Questo può essere scritto in C++ come allocatore di classe, una classe che deve soddisfare i requisiti della Allocator (concetto): http://en.cppreference.com/w/cpp/concept/Allocator. Per esempio (incompleto):

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) {} 
}; 

Se può quindi essere utilizzato con contenitori STL, come:

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

utilizza la memoria sulla scheda SD per le componenti della vec. Qui sono non-volatile e destinati esclusivamente all'uso all'interno del programma, non per la memorizzazione persistente sulla scheda SD.

L'allocatore standard C++ è std::allocator, che alloca memoria regolare come malloc e free.

Boost sembra fornire un allocatore che gestisce la segmentazione, in una regione di memoria definito personalizzato:

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

per la memorizzazione persistente, come ad esempio una scheda SD, può essere meglio per definire una fissa struttura e layout per i dati sulla scheda SD, quindi leggere/scrivere su di essa.

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; 
} 

secondo caso (istruzioni speciali)

Se lettura/scrittura sulla scheda SD non corrispondono alle istruzioni di accesso alla memoria regolari l'hardware, i dati su di esso non è possibile accedere direttamente utilizzando prime volatile puntatori.

Se l'obiettivo è ancora di accedervi in ​​questo modo, sarebbe necessaria una classe come MemDef. Potrebbe essere meglio trattare la scheda SD come un file/stream, e invece scrivere/leggere interi blocchi di dati da/per esso, usando funzioni come fopen, fread, fprintf o simili.

Gli oggetti devono essere serializzati/non serializzati per questo. Copia di un struct come memoria greggio, come

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

funziona finché il struct è un PODType e non contiene alcuna puntatori/riferimenti, cioè tipi cui rappresentazione interna dipende dalle indirizzi di memoria. Dipende anche dal layout di memoria della piattaforma (allineamento, struct padding), endianness, rappresentazione di float, CHAR_BIT, ecc. Per il supporto multipiattaforma (ad esempio quando la scheda SD viene letta da un altro dispositivo con un altro microcontrollore, qualche formato di file avrebbe bisogno di essere usato al posto.

può anche essere possibile (ma difficile) per definire una classe personalizzata Allocator, che utilizza una classe come MemDef come tipo di puntatore.

2

Bene, nel mondo C++ per astrarre la memoria di solito si scrive un allocatore personalizzato. Lungo le linee

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 
    } 

    ....... 
Problemi correlati